#pragma once

#include <iostream>
#include <functional>
#include <unordered_map>
#include <assert.h>
#include "Log.hpp"
#include "Sock.hpp"
#include "Err.hpp"
#include "Epoller.hpp"
#include "Util.hpp"

namespace tcpServer
{
    class Connection;
    class TcpServer;

    static const uint16_t defaultport = 8888;
    static const int num = 64;

    using func_t = std::function<void(Connection *)>;

    class Connection // 把每一个accept到的套接字信息单独存储
    {

    public:
        Connection(int sock) : sock_(sock), tsp_(nullptr) {}
        void Register(func_t r, func_t s, func_t e)
        {
            recver_ = r;
            sender_ = s;
            excepter_ = e;
        }
        ~Connection() {}

    public:
        int sock_;
        std::string inbuffer_;  // 输入缓冲区
        std::string outbuffer_; // 输出缓冲区

        func_t recver_;   // 从sock_ 读
        func_t sender_;   // 向sock_ 写
        func_t excepter_; // 处理 sock_ IO的时候上面的异常事件

        TcpServer *tsp_; // ？？可以被省略，但是想加一下
    };

    class TcpServer
    {
    public:
        TcpServer(uint16_t port = defaultport) : port_(port), revs_(nullptr)
        {
        }

        void InitServer()
        {
            // 1. 创建套接字
            sock_.Socket();
            sock_.Bind(port_);
            sock_.Listen();
            // 2. 创建epoll模型
            epoller_.Create();
            // 3. 将目前唯一的一个sock，添加到epoller中 这里epoll的工作模式是ET，所以需要将之前的fd设置非阻塞的
            // listensock_也是一个socket，但是也要看做一个connection
            AddConnection(sock_.Fd(), EPOLLIN | EPOLLET,
                          std::bind(&TcpServer::Accepter, this, std::placeholders::_1), nullptr, nullptr);
            revs_ = new struct epoll_event[num];
            num_ = num;
        }
        // 事件派发器
        void Dispatcher()
        {
            int timeout = -1;
            while (true)
            {
                Loop(timeout);
                logMessage(DEBUG, "timeout...");
            }
        }
        ~TcpServer()
        {
            sock_.Close();
            epoller_.Close();
            if (nullptr == revs_)
                delete[] revs_;
        }

    private:
        void Recver(Connection *conn)
        {
            char buffer[1024];
            while (true)
            {
                ssize_t s = recv(conn->sock_, buffer, sizeof(buffer) - 1, 0);
                if (s > 0)
                {
                    buffer[s] = 0;
                    conn->inbuffer_ += buffer; // 将读到的数据入队列
                }
                else if (s == 0)
                {
                    if (conn->excepter_)
                        conn->excepter_(conn);
                }
                else
                {
                    if (errno == EAGAIN || errno == EWOULDBLOCK) // 表示没数据
                        break;
                    else if (errno == EINTR) // 读的时候，被信号中断了
                        continue;
                    else
                    {
                        if (conn->excepter_)
                            conn->excepter_(conn);
                    }
                }
            }
            logMessage(DEBUG, "[%d] -> %s", conn->sock_, conn->inbuffer_.c_str());
        }
        void Sender(Connection *conn)
        {
        }
        void Excepter(Connection *conn)
        {
        }
        void Accepter(Connection *conn)
        {
            logMessage(DEBUG, "accept in");
            for (;;)
            {
                std::string clientip;
                uint16_t clientport;
                int err = 0;
                int sock = sock_.Accept(&clientip, &clientport, &err);
                if (sock > 0)
                {
                    AddConnection(
                        sock, EPOLLIN | EPOLLET,
                        std::bind(&TcpServer::Recver, this, std::placeholders::_1),
                        std::bind(&TcpServer::Sender, this, std::placeholders::_1),
                        std::bind(&TcpServer::Excepter, this, std::placeholders::_1));
                    logMessage(DEBUG, "get a new link, info: [%s:%d]", clientip.c_str(), clientport);
                }
                else
                {
                    if (err == EAGAIN || err == EWOULDBLOCK)
                        break;
                    else if (err == EINTR)
                        continue;
                    else
                        break;
                }
            }
            logMessage(DEBUG, "accept out");
        }

        void AddConnection(int sock, uint32_t events, func_t recver, func_t sender, func_t excepter)
        {
            // 1. 首先要为该sock创建Connection，并初始化，并添加到connettions_
            if (events & EPOLLET) // 这个epoll设置了ET模式，就让sock非阻塞
                Util::SetNonBlock(sock);
            Connection *conn = new Connection(sock); // ?
            // 2. 给对应的sock设置对应的回调处理方法
            conn->Register(recver, sender, excepter);

            // 2. 其次将sock与它要关心的事件 "写透式" 注册到epoll中，让epoll帮我们关心
            bool r = epoller_.AddEvent(sock, events);
            assert(r);
            (void)r;

            // 3. 将key value 添加到connecttions_
            connecttions_.insert(std::pair<int, Connection *>(sock, conn));
            logMessage(DEBUG, "add new sock ：%d in epoll and unordered_map", sock);
        }
        bool IsConnectionExists(int sock)
        {
            auto iter = connecttions_.find(sock);
            return iter != connecttions_.end();
        };
        void Loop(int timeout)
        {
            int n = epoller_.Wait(revs_, num_, timeout); // 获取已经就绪事件
            for (int i = 0; i < n; i++)
            {
                int sock = revs_[i].data.fd;
                uint32_t events = revs_[i].events;

                // 将所有的异常问题，全部转化 为读写问题
                if (events & EPOLLERR)
                    events |= (EPOLLIN | EPOLLOUT);
                if (events & EPOLLHUP)
                    events |= (EPOLLIN | EPOLLOUT);
                // listent事件就绪
                if ((events & EPOLLIN) && IsConnectionExists(sock) && connecttions_[sock]->recver_)
                {
                    connecttions_[sock]->recver_(connecttions_[sock]);
                }
                if ((events & EPOLLOUT) && IsConnectionExists(sock) && (connecttions_[sock]->sender_))
                    connecttions_[sock]->sender_(connecttions_[sock]);
            }
        }

    private:
        uint16_t port_;
        Sock sock_;
        Epoller epoller_;
        std::unordered_map<int, Connection *> connecttions_; // 所有的链接集合
        struct epoll_event *revs_;
        int num_; // 存放就绪事件的fd到数组
    };
} // namespace tcpServer